<?php
//需要同步httpService 的参数设置

namespace lib\Server\Service;
;

use App\App;
use lib\Server\Http\Request;
use lib\Server\Http\Response;

class TcpHttpService
{
	private $method;
	private $path_info;
	private $http_protocol;

	public $response;
//	public $rawResponse;
	public $raw_context;

	public  $request;
	private $header;
	private $body;
	private $get;
	private $files;
	private $cookie;

	private $data;
	private $fd_info;

	static public $session_id; #回话id

	public $base_namespace;

	public function __construct($container=null)
	{
		echo 'TcpHttpService'.PHP_EOL;
		$this->base_namespace = $container;
	}

	/**
	 * 处理请求
	 * @param $server
	 * @param $fd
	 * @param $reactor_id
	 * @param $data
	 */
	static public function handler($server, $fd, $reactor_id, $data)
	{

		$http             = (new self());
		self::$session_id = uniqid(time());

		echo self::$session_id.PHP_EOL;

		$http->fd_info    = $server->connection_info($fd);

		if (!$http->unpack($data)) {
			$server->close($fd);
		}
		else {
			$http->content();

			App::run($http);

			$server->send($fd, $http->response);
			$http->destroy();
		}
	}


	/**
	 * 解包
	 * @param $data
	 * @return bool
	 */
	public function unpack($data)
	{
		$this->data = explode("\r\n\r\n", $data);
		$header     = explode("\r\n", $this->data[0]);
		unset($this->data[0]);

		$this->raw_context = join("\r\n\r\n", $this->data);


		foreach ($header as $key => $val) {
			if ($key === 0) {
				list($this->method, $this->path_info, $this->http_protocol) = explode(" ", $val, 3);
			}
			else {
				$headerRow                               = explode(":", $val);
				$this->header[strtolower($headerRow[0])] = trim($headerRow[1], ' ');
			}
		}

		if (@$this->header['content-type']) {
			$content_type                                                       = explode(';', $this->header['content-type']);
			$this->header['content-type']                                       = $content_type[0];
			$content_type_params                                                = explode('=', $content_type[1]);
			$this->header['content-type-params'][trim($content_type_params[0])] = $content_type_params[1];
		}

		if (!$this->method || !$this->http_protocol) {
			return false;
		}

		return true;
	}


	/**
	 *  格式化payload
	 */
	public function content()
	{
		$contentType = @$this->header['content-type'];
		$raw_context = false;
		switch (strtolower($contentType)) {
//			case "application/json":
//				$this->body = is_json($this->raw_context) ?: [];
//				break;
//			case "application/xml":
//				$this->body = is_xml($this->raw_context) ?: [];
//				break;
			case "application/x-www-form-urlencoded":
				parse_str($this->raw_context, $output);
				$this->body = $output ?: [];
				break;
			case "multipart/form-data":
				$this->multipartFromData();
				break;
			default:
				$raw_context = $this->raw_context;
				break;
		}

		$this->deCookie();
		$this->deUrls();
		$server = [
			'request_method' => $this->method,
			'path_info' => $this->path_info,
			'remote_addr' => $this->fd_info['remote_ip'],
			'remote_port' => $this->fd_info['remote_port'],
			'server_port' => $this->fd_info['server_port'],
		];

		$this->request = new Request($this->header, $this->get, $this->body, $raw_context, $this->files, $this->cookie, $server);

		$this->response = new Response($this->request);

		return $this;
	}

	public function deCookie()
	{
		if (!$this->header['cookie']) return false;

		$cookies = explode(';', $this->header['cookie']);

		foreach ($cookies as $val) {
			$_tmp                   = explode('=', $val);
			$this->cookie[$_tmp[0]] = $_tmp[1];
		}
	}

	public function deUrls()
	{
		$url_params = @explode('#', @explode('?', $this->path_info)[1])[0];
		$this->get  = parse_str($url_params);
	}


	/**
	 * 回收资源
	 */
	public function destroy()
	{
		#删除临时文件
		delete_dir(TMP_DIR . DIRECTORY_SEPARATOR . self::$session_id);

		$this->method = $this->raw_context = $this->request = $this->response = $this->path_info = $this->header = $this->http_protocol = $this->body = $this->files = null;
	}

	private function multipartFromData()
	{
		$body = explode('--' . $this->header['content-type-params']['boundary'], $this->raw_context);
		unset($body[0], $body[count($body)]);

		foreach ($body as $value) {
			$_     = explode("\r\n\r\n", $value);
			$_info = explode("\r\n", $_[0]);

			$_tmp = [];

			$_tmp_arr = explode(';', $_info[1]);

			foreach ($_tmp_arr as $k => $v) {
				if (0 === $k) {
					$__tmp                 = explode(':', $v);
					$_tmp[trim($__tmp[0])] = trim($__tmp[1]);
				}
				else {
					$__tmp                 = explode('=', $v);
					$_tmp[trim($__tmp[0])] = trim($__tmp[1], '"');
				}
			}
			if (isset($_tmp['filename'])) {
				$file_path     = create_tmp_file(TMP_DIR . DIRECTORY_SEPARATOR . self::$session_id, 'haoge.tmpfile.' . uniqid(), $_[count($_) - 1]);
				$this->files[] = [
					'size' => filesize($file_path),
					'name' => $_tmp['filename'],
					//					'tmp' => $file_path,
					'tmp_name' => $file_path,
					'error' => !(int)$file_path,
					'type' => trim(explode(':', $_info[2])[1])
				];
			}
			else {
				$this->body[$_tmp['name']] = trim($_[count($_) - 1]);
			}

		}
	}


}